<template>
  <div class="login-wrapper">
    <div class="modal">
      <a-icon
        type="close"
        @click="$store.commit('UPDATE_LOGIN_VISIBLE', false); $emit('close-modal')"
      />
      <a-form-model v-if="!isCodeLogin" ref="loginForm" :model="loginForm">
        <h3 v-if="!isEmailVisible">{{ isRegister ? isBindUserName ? '用户名密码绑定' : '用户注册' : '密码登录' }}</h3>
        <h3 v-else>邮箱登录</h3>
        <!-- 用户名密码登录 -->
        <div v-if="!isEmailVisible">
          <a-form-model-item placeholder="" prop="username">
            <a-input
              v-model="loginForm.username"
              :placeholder="isRegister ? '用户名' : '用户名/邮箱'"
              size="large"
            />
          </a-form-model-item>
          <a-form-model-item prop="password">
            <a-input-password
              v-model="loginForm.password"
              size="large"
              placeholder="密码"
            />
          </a-form-model-item>
          <a-form-model-item v-if="isRegister" prop="confirmPassword">
            <a-input-password
              v-model="loginForm.confirmPassword"
              size="large"
              placeholder="密码确认"
            />
          </a-form-model-item>
          <a-form-model-item class="input-image-code" prop="code" style="display: flex">
            <a-input
              v-model="loginForm.code"
              size="large"
              class="code-input"
              placeholder="验证码"
            />
            <div
              style="cursor: pointer"
              class="code"
              @click="getVerificationcode"
              v-html="codeImage"
            ></div>
          </a-form-model-item>
        </div>

        <!-- 邮箱验登录 -->
        <div v-else>
          <a-form-model-item prop="email">
            <a-input
              v-model="loginForm.email"
              placeholder="邮箱"
              size="large"
            >
              <div slot="suffix" class="send-email-code">
                <p v-if="!countdown && !sendLoading" @click="sendEmail">
                  发送验证码
                </p>
                <a-icon v-if="sendLoading" type="loading" />
              </div>
            </a-input>
          </a-form-model-item>
          <a-form-model-item prop="emailCode">
            <a-input
              v-model="loginForm.emailCode"
              size="large"
              placeholder="6位数字验证码"
            >
              <div slot="suffix" class="send-email-code">
                <span v-if="countdown && !sendLoading"
                  >{{ countdown }} s后重新发送</span
                >
              </div>
            </a-input>
          </a-form-model-item>
        </div>

        <div style="display: flex; align-items: center;">
          <a-button
            v-if="isEmailVisible"
            style="padding: 0; font-size: 12px"
            type="link"
            size="small"
            @click="isEmailVisible = false"
            >用户名密码登录</a-button
          >
          <a-button
            v-if="!isEmailVisible && !isBindUserName"
            style="padding: 0; font-size: 12px;"
            type="link"
            size="small"
            @click="isRegister = !isRegister"
            >{{ !isRegister ? '前往注册' : '已有账号，前往登录' }}</a-button
          >
        </div>
        <a-button
          :disabled="disabledButton"
          style="height: 36px; letter-spacing: 1px;"
          block
          size="large"
          type="primary"
          @click="submituserInfo">{{ isRegister ? isBindUserName ? '立即绑定' : '立即注册' : isEmailVisible ? '立即登录/注册' : '立即登录' }}</a-button
        >
        <div class="login-type-list" v-if="!isBindUserName">
          <p class="tip" v-if="!isBindUserName"><span>注册、登录</span> 后即可进行文章发布</p>
          <p @click="isCodeLogin = true"><img src="~assets/images/wx-logo.png" alt=""></p>
          <p @click="isEmailVisible = true"><img src="~assets/images/email-logo.png" alt=""></p>
          <p>
            <a
              href="https://gitee.com/oauth/authorize?client_id=57a64666d7aa79411b3352e8805b6e52cf0c64d415e56756c7414a914e01dac8&redirect_uri=https://gimi.zdxblog.cn/&response_type=code&state=gitee">
              <img src="~assets/images/gitee-logo.png" alt="">
            </a>
          </p>
          <p>
            <a
              href="https://github.com/login/oauth/authorize?client_id=Ov23liCiZWWku8B1MMog&https://gimi.zdxblog.cn&scope=user:email&state=github">
              <img src="~assets/images/github-logo.png" alt="">
            </a>
          </p>
        </div>
      </a-form-model>

      <!-- 微信扫码登录 -->
      <div class="sacnqrcode-login-modal" v-if="isCodeLogin">
        <div class="mini-web-code">
          <a-spin v-show="!qrcodeImage" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
            <a-icon slot="indicator" type="loading" style="font-size: 24px" spin />
          </a-spin>
          <img v-show="qrcodeImage" :src="qrcodeImage" alt="code" />
          <div class="finish-logo" v-if="loginSuccess">
            <svg width="64" height="64" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
              <path class="finish-path" d="M4 25.1818 L16.875 39 L43 17" stroke="rgb(7,193,96)" stroke-width="5" stroke-linecap="butt" stroke-linejoin="butt"/>
            </svg>
          </div>
        </div>
        <p>{{ isBindWx ? '打开微信扫一扫，绑定微信' : '打开微信扫一扫，快速登录/注册' }}</p>
        <span v-if="!isBindWx" @click="isCodeLogin = false">其他方式登录</span>
      </div>
    </div>
  </div>
</template>

<script>
import config from '~/nuxt.config'
import createSocket from '~/util/socket'
import { encrypt, newRandomId } from '~/util'
export default {
  props: {
    isBindWx: {
      type: Boolean,
      default: false
    },
    isBindUserName: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      socket: null,
      isCodeLogin: Boolean(this.isBindWx),
      loginForm: {
        username: '',
        password: '',
        confirmPassword: '',
        code: '',
        email: '',
        emailCode: ''
      },
      isRegister: Boolean(this.isBindUserName),
      codeImage: '',
      qrcodeImage: '',
      countdown: null,
      sendLoading: false,
      isEmailVisible: false,
      loginSuccess: false
    }
  },

  created () {
    if (!this.isBindWx) {
      this.getVerificationcode()
    }
    if (!this.isBindUserName) {
      this.getMiniWebQRCode()
    }
  },

  methods: {
    async getVerificationcode () {
      try {
        const { data } = await this.$axios.get('/gimishare/api/v1/unit/verificatecode')
        this.codeImage = data
      } catch (error) {
        console.log(error)
      }
    },

    async getMiniWebQRCode () {
      try {
        const authId = newRandomId()
        const API = !this.isBindWx ? '/gimishare/api/v1/unit/getqrcode' : '/gimishare/api/v1/users/generateqrcode'
        const { data } = await this.$axios.get(`${API}?authId=${authId}`)
        this.qrcodeImage = data
        this.initWebsocket(authId)
      } catch (error) {
        console.log(error)
      }
    },

    /**
     * init websocket receive message
     */
    initWebsocket (authId) {
      const protocol = location.protocol === 'http:' ? 'ws' : 'wss'
      const hostname = config.dev ? 'localhost:4000' : location.hostname
      this.socket = createSocket(`${protocol}://${hostname}/socket/message?authId=${authId}`, {
        onopen: () => {},

        onmessage: (e) => {
          if (e.data.includes('messagepush')) {
            this.loginSuccess = true
            const message = JSON.parse(e.data)
            this.$cookies.set('ACCESS_TOKEN', message.accessToken, {
              path: '/',
              maxAge: 60 * 60 * 24 * 7
            })
            setTimeout(() => {
              location.reload()
            }, 1500)
          }
        },

        onclose () {},

        onerror () {}
      })
    },

    /**
     * username or email login
     */
    submituserInfo () {
      if (!this.disabledButton) {
        if (!this.isRegister) {
          this.userEnterLogin()
        } else {
          if (this.isBindUserName) {
            return this.userBindUserName()
          }
          this.userEnterRegister()
        }
      }
    },

    async userBindUserName () {
      if (this.loginForm.password !== this.loginForm.confirmPassword) {
        return this.$message.info('两次输入的密码不一致')
      }
      const { data: aesPublicKey } = await this.$axios.get('/gimishare/api/v1/unit/getpublickey')
      try {
        const searchParams = {
          ...this.loginForm,
          password: encrypt(
            this.loginForm.password,
            aesPublicKey.aesKey,
            aesPublicKey.aesIv
          ),
          confirmPassword: encrypt(
            this.loginForm.confirmPassword,
            aesPublicKey.aesKey,
            aesPublicKey.aesIv
          )
        }
        const user = await this.$axios.post('/gimishare/api/v1/users/bindusername', searchParams)
        this.$message.success('绑定用户名成功')
        this.$store.commit('UPDATE_USER_INFO', user.data)
        this.$emit('close-modal')
      } catch (error) {}
    },

    /**
     * user login
     * @param { Boolean } isRegisterEnter 是否注册后登录
     */
    async userEnterLogin (isRegisterEnter) {
      try {
        const searchParams = this.isEmailVisible ? this.emailLoginGetParams() : await this.passwordLoginGetParams()
        if (typeof searchParams === 'object') {
          const { data } = await this.$axios.post('/gimishare/api/v1/users/login', searchParams)
          !isRegisterEnter && this.$message.success('登录成功')
          this.$cookies.set('ACCESS_TOKEN', data.accessToken, {
            path: '/',
            maxAge: 60 * 60 * 24 * 7
          })
          this.$store.commit('UPDATE_USER_INFO', data)
          location.reload()
        }
      } catch (error) {}
    },

    emailLoginGetParams () {
      const REG_EMAIL = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
      if (!REG_EMAIL.test(this.loginForm.email)) {
        return this.$message.info('邮箱格式不正确')
      }
      return {
        email: this.loginForm.email,
        code: this.loginForm.emailCode,
        emailLogin: true
      }
    },

    async passwordLoginGetParams () {
      try {
        const { data: aesPublicKey } = await this.$axios.get('/gimishare/api/v1/unit/getpublickey')
        return {
          ...this.loginForm,
          password: encrypt(
            this.loginForm.password,
            aesPublicKey.aesKey,
            aesPublicKey.aesIv
          )
        }
      } catch (error) {
        return false
      }
    },

    /**
     * user register
     */
    async userEnterRegister () {
      if (this.loginForm.password !== this.loginForm.confirmPassword) {
        return this.$message.info('两次输入的密码不一致')
      }
      if (!/^[a-zA-Z0-9@]+$/.test(this.loginForm.username)) {
        return this.$message.info('用户名只支持英文字符、数字和@符')
      }
      const { data: aesPublicKey } = await this.$axios.get('/gimishare/api/v1/unit/getpublickey')
      try {
        const searchParams = {
          ...this.loginForm,
          password: encrypt(
            this.loginForm.password,
            aesPublicKey.aesKey,
            aesPublicKey.aesIv
          ),
          confirmPassword: encrypt(
            this.loginForm.confirmPassword,
            aesPublicKey.aesKey,
            aesPublicKey.aesIv
          )
        }
        await this.$axios.post('/gimishare/api/v1/users/registeruser', searchParams)
        this.$message.success('注册成功')
        this.userEnterLogin(true)
      } catch (error) {}
    },

    /**
     * send email
     */
    async sendEmail () {
      const REG_EMAIL = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
      if (!REG_EMAIL.test(this.loginForm.email)) {
        return this.$message.info('邮箱格式不正确')
      }
      this.sendLoading = true
      try {
        await this.$axios.get(
          `/gimishare/api/v1/unit/emailcode?email=${this.loginForm.email}`
        )
        this.countdown = 60
        this.countdownTimer = setInterval(() => {
          this.countdown--
          if (this.countdown === 0) {
            this.countdown = null
            clearInterval(this.countdownTimer)
          }
        }, 1000)
      } catch (error) {
      } finally {
        this.sendLoading = false
      }
    }
  },

  computed: {
    disabledButton () {
      const { isEmailVisible, loginForm, isRegister } = this
      if (isRegister) {
        return !loginForm.username || !loginForm.password || !loginForm.code || !loginForm.confirmPassword
      }
      if (isEmailVisible) {
        return !loginForm.email || !loginForm.emailCode
      } else {
        return !loginForm.username || !loginForm.password || !loginForm.code
      }
    }
  },

  beforeDestroy () {
    this.socket?.close()
  }
}
</script>
